package com.hs.egova.hibernate;

import com.hs.egova.base.Pagination;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.hibernate.*;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.classic.QueryTranslatorImpl;
import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import javax.persistence.Column;
import javax.persistence.Table;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * 使用Hibernate实现baseDAO接口
 * @author husheng
 * @version v1.0
 * @date 2021/7/26 15:29
 * @email husheng@egova.com.cn
 */
@Slf4j
public class HibernateBaseDao<T, ID extends Serializable> extends HibernateDaoSupport implements BaseDao<T, ID> {

    private Class<T> persistentClass;
    /**
     * 锁住对象
     * @param obj
     */
    @Override
    public void lock(Object obj) {
        Session session = getSession();
        session.buildLockRequest(LockOptions.UPGRADE).lock(obj);
    }
    @Override
    public T saveOrUpdate(T o){
        Session session = getSession();
        try{
            session.saveOrUpdate(o);
            return o;
        }catch(HibernateException e){
            log.error("保存或更新对象错误！{}", e);
            throw e;
        }
    }

    @Override
    public T save(T o){
        Session session = getSession();
        try{
            session.save(o);
            session.flush();
            return o;
        }catch(HibernateException e){
            log.error("插入对象错误！", e);
            throw e;
        }
    }

    /**
     * 批量插入
     * @param list
     * @return
     */
    @Override
    public List<T> save(List<T> list){
        Session session = getSession();
        try{
            if(list != null){
                for(T o : list){
                    session.save(o);
                }
                session.flush();
            }
            return list;
        }catch(HibernateException e){
            log.error("批量插入对象错误！", e);
            throw e;
        }
    }

    @Override
    public List<T> saveOrUpdate(List<T> list){
        Session session = getSession();
        try{
            if(list != null){
                for(T o : list){
                    session.saveOrUpdate(o);
                }
            }
            return list;
        }catch(HibernateException e){
            log.error("批量保存或更新对象错误！", e);
            throw e;
        }
    }

    @Override
    public void deleteByID(ID id){
        Session session = getSession();
        try{
            session.delete(findById(id));
        }catch(HibernateException e){
            log.error("根据主键删除对象错误！", e);
            throw e;
        }
    }

    @Override
    public void delete(List<T> list){
        Session session = getSession();
        try{
            if(list != null){
                for(T o : list){
                    session.delete(o);
                }
            }
        }catch(HibernateException e){
            log.error("删除对象错误！", e);
            throw e;
        }
    }

    @Override
    public void delete(T o){
        Session session = getSession();
        try{
            session.delete(o);
        }catch(HibernateException e){
            log.error("删除对象错误！", e);
            throw e;
        }
    }

    @Override
    public int deleteByWhere(String where){
        String hql = " delete from " + this.getPersistentClass().getName() + " where " + where;
        return this.execute(hql);
    }

    @Override
    public int deleteByWhere(String where, Object... params){
        String hql = " delete from " + this.getPersistentClass().getName() + " where " + where;
        return this.execute(hql, params);
    }

    @Override
    public int deleteByWhere(String where, Map<String, Object> map){
        String hql = " delete from " + this.getPersistentClass().getName() + " where " + where;
        return this.execute(hql, map);
    }

    @Override
    @SuppressWarnings("unchecked")
    public T findById(ID id){
        Session session = getSession();
        try{
            return (T) session.get(getPersistentClass(), id);
        }catch(HibernateException e){
            log.error("获取对象错误！", e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public T findByIdLockMode(ID id){
        Session session = getSession();
        try{
            return (T) session.get(getPersistentClass(), id, LockOptions.UPGRADE);
        }catch(HibernateException e){
            log.error("获取对象错误！", e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> listAll(){
        Session session = getSession();
        try{
            Query query = session.createQuery(" from " + this.getPersistentClass().getName());
            return query.list();
        }catch(HibernateException e){
            log.error("获取所有对象错误！", e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> listAll(int offset, int max){
        Session session = getSession();
        try{
            Query query = session.createQuery(" from " + this.getPersistentClass().getName());
            if(max > 0){
                query.setMaxResults(max);
            }
            if(offset > 0){
                query.setFirstResult(offset);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("获取分页对象列表错误！", e);
            throw e;
        }
    }

    @Override
    public Long countAll(){
        Session session = getSession();
        try{
            Query query = session.createQuery(" select count(*) from "
                    + this.getPersistentClass().getName());
            return (Long) query.list().get(0);
        }catch(HibernateException e){
            log.error("获取所有对象数量错误！", e);
            throw e;
        }
    }

    @Override
    public Long countByWhere(String where, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(" select count(*) from "
                    + this.getPersistentClass().getName() + " where " + where);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return (Long) query.list().get(0);
        }catch(HibernateException e){
            log.error("hqlWhere获取对象数量错误！", e);
            throw e;
        }
    }

    @Override
    public Long countByWhere(String where, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(" select count(*) from "
                    + this.getPersistentClass().getName() + " where " + where);
            setParameter(query, map);
            return (Long) query.list().get(0);
        }catch(HibernateException e){
            log.error("hqlWhere获取对象数量错误！", e);
            throw e;
        }
    }

    @Override
    public Long countByWhere(String where){
        Session session = getSession();
        try{
            Query query = session.createQuery(" select count(*) from "
                    + this.getPersistentClass().getName() + " where " + where);
            return (Long) query.list().get(0);
        }catch(HibernateException e){
            log.error("hqlWhere获取对象数量错误！", e);
        }
        return null;
    }

    @Override
    public int execute(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.executeUpdate();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public int execute(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            return query.executeUpdate();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    /**
     * 为查询设置参数
     * @param map
     * @param query
     */
    private void setParameter(Query query, Map<String, Object> map){
        if(map != null){
            for(Map.Entry<String, Object> entry : map.entrySet()){
                if(entry.getValue() == null){
                    query.setParameter(entry.getKey(), entry.getValue());
                }else if(entry.getValue() instanceof Collection<?>){
                    query.setParameterList(entry.getKey(), (Collection<?>)entry.getValue());
                }else if(entry.getValue().getClass().isArray()){
                    query.setParameterList(entry.getKey(), (Object[])entry.getValue());
                }else{
                    query.setParameter(entry.getKey(), entry.getValue());
                }
            }
        }
    }

    @Override
    public int execute(String hql){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            return query.executeUpdate();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public List<T> queryByWhere(String where){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return query(hql);
    }

    @Override
    public List<T> queryByWhere(String where, Object... params){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return query(hql, params);
    }

    @Override
    public List<T> queryByWhere(String where, Map<String, Object> map){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return query(hql, map);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> query(String hql){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> queryLockMode(String hql){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            query.setLockOptions(LockOptions.UPGRADE);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> query(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> queryLockMode(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            query.setLockOptions(LockOptions.UPGRADE);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> query(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> queryLockMode(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            query.setLockOptions(LockOptions.UPGRADE);
            setParameter(query, map);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> queryForMapList(String hql){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> queryForMapList(String hql, Object... params){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> queryForMapList(String hql, Map<String, Object> map){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public List<T> querySubListByWhere(String where, int offset, int max, Object... params){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return querySubList(hql, offset, max, params);
    }

    @Override
    public List<T> querySubListByWhere(String where, int offset, int max, Map<String, Object> map){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return querySubList(hql, offset, max, map);
    }

    @Override
    public List<T> querySubListByWhere(String where, int offset, int max){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return querySubList(hql, offset, max);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> querySubMapList(String hql, int offset, int max, Object... params){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> querySubMapList(String hql, int offset, int max, Map<String, Object> map){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> querySubMapList(String hql, int offset, int max){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> querySubList(String hql, int offset, int max, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> querySubList(String hql, int offset, int max, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> querySubList(String hql, int offset, int max){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            if(offset > 0){
                query.setFirstResult(offset);
            }
            if(max > 0){
                query.setMaxResults(max);
            }
            return query.list();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Object getUniqueObj(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.uniqueResult();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Object getUniqueObj(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            return query.uniqueResult();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public String getString(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return obj == null ? null : obj.toString();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public String getString(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return obj == null ? null : obj.toString();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Integer getInteger(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return obj == null ? null : (Integer) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Integer getInteger(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return obj == null ? null : (Integer) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Long getLong(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return obj == null ? null : (Long) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Long getLong(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return obj == null ? null : (Long) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Date getDate(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return obj == null ? null : (Date) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Date getDate(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return obj == null ? null : (Date) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Float getFloat(String hql, Object... params){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return toFloat(obj);
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Float getFloat(String hql, Map<String, Object> map){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return toFloat(obj);
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public Object getUniqueObj(String hql){
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            return query.uniqueResult();
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> getMap(String hql){
        mapHqlCheck(hql);
        Object obj = getUniqueObj(hql);
        return obj == null ? null : (Map<String, Object>) obj;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> getMap(String hql, Object... params){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            Object obj = query.uniqueResult();
            return obj == null ? null : (Map<String, Object>) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> getMap(String hql, Map<String, Object> map){
        mapHqlCheck(hql);
        Session session = getSession();
        try{
            Query query = session.createQuery(hql);
            setParameter(query, map);
            Object obj = query.uniqueResult();
            return obj == null ? null : (Map<String, Object>) obj;
        }catch(HibernateException e){
            log.error("执行hql错误！hql:{}", hql, e);
            throw e;
        }
    }

    @Override
    public String getString(String hql){
        Object obj = getUniqueObj(hql);
        return obj == null ? null : obj.toString();
    }

    @Override
    public Integer getInteger(String hql){
        Object obj = getUniqueObj(hql);
        return obj == null ? null : (Integer) obj;
    }

    @Override
    public Long getLong(String hql){
        Object obj = getUniqueObj(hql);
        return obj == null ? null : (Long) obj;
    }

    @Override
    public Date getDate(String hql){
        Object obj = getUniqueObj(hql);
        return obj == null ? null : (Date) obj;
    }

    @Override
    public Float getFloat(String hql){
        Object obj = getUniqueObj(hql);
        return toFloat(obj);
    }

    @Override
    public void loadLazyEntity(Object entity){
        try{
            Hibernate.initialize(entity);
        }catch(HibernateException e){
            log.error("载入Lazy Entity错误！", e);
            throw e;
        }
    }

    @Override
    public String cmdToSql(String hql){
        QueryTranslator queryTranslator = new QueryTranslatorImpl(hql, hql, Collections.EMPTY_MAP,
                (SessionFactoryImplementor) getSession().getSessionFactory());
        queryTranslator.compile(Collections.EMPTY_MAP, false);
        return queryTranslator.getSQLString();
    }

    @Override
    public Pagination<T> getPaginationByWhere(String where, int currentPage, int numPerPage){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return getPagination(hql, currentPage, numPerPage);
    }

    @Override
    public Pagination<T> getPaginationByWhere(String where, int currentPage, int numPerPage, Object... params){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return getPagination(hql, currentPage, numPerPage, params);
    }

    @Override
    public Pagination<T> getPaginationByWhere(String where, int currentPage, int numPerPage, Map<String, Object> map){
        String hql = " from " + this.getPersistentClass().getName() + " where " + where;
        return getPagination(hql, currentPage, numPerPage, map);
    }

    @Override
    public Pagination<T> getPagination(String hql, int currentPage, int numPerPage){
        int totalRows = this.getLong(getCountHqlOrSql(hql)).intValue();
        //获取列表
        List<T> list = this.querySubList(hql, (currentPage - 1) * numPerPage, numPerPage);
        return new Pagination<T>(currentPage, numPerPage, totalRows, list);
    }

    @Override
    public Pagination<T> getPagination(String hql, int currentPage, int numPerPage, Object... params){
        //获取计数
        int totalRows = this.getLong(getCountHqlOrSql(hql), params).intValue();
        //获取列表
        List<T> list = this.querySubList(hql, (currentPage - 1) * numPerPage, numPerPage, params);
        return new Pagination<T>(currentPage, numPerPage, totalRows, list);
    }

    /**
     * 获取计数hql 或 sql 逻辑不够严谨
     * @param hqlOrSql
     * @return
     */
    private String getCountHqlOrSql(String hqlOrSql){
        if(!hqlOrSql.startsWith(" ")){
            hqlOrSql = " ".concat(hqlOrSql);
        }
        int start = hqlOrSql.toLowerCase().indexOf(" from ");
        //去掉后面的order by
        int pos = hqlOrSql.toLowerCase().lastIndexOf(" order by ");
        //如果order by 之后还有括号（即内部嵌套），就不去掉
        int end =  pos > -1 ? (hqlOrSql.substring(pos).indexOf(")") > -1 ? hqlOrSql.length() : pos) : hqlOrSql.length();
        return " select count(*) " + hqlOrSql.substring(start, end);
    }

    @Override
    public Pagination<T> getPagination(String hql, int currentPage, int numPerPage, Map<String, Object> map){
        int totalRows = this.getLong(getCountHqlOrSql(hql), map).intValue();
        //获取列表
        List<T> list = this.querySubList(hql, (currentPage - 1) * numPerPage, numPerPage, map);
        return new Pagination<T>(currentPage, numPerPage, totalRows, list);
    }

    @Override
    public Pagination<T> getPaginationForSql(String sql, int currentPage, int numPerPage) {
        Session session = getSession();
        try {
            //获取计数
            String countSql = getCountHqlOrSql(sql);
            NativeQuery countQuery = session.createNativeQuery(countSql);
            Object countObj = countQuery.uniqueResult();
            int totalRows = getIntValue(countObj);
            //获取列表
            Query query = session.createNativeQuery(sql);
            int offset = (currentPage - 1) * numPerPage;
            if (offset > 0) {
                query.setFirstResult(offset);
            }
            if (numPerPage > 0) {
                query.setMaxResults(numPerPage);
            }
            query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> list = query.list();
            return new Pagination<T>(currentPage, numPerPage, totalRows, null, list);
        } catch(HibernateException e) {
            log.error("执行sql错误！sql:{}",  sql, e);
            throw e;
        }
    }

    @Override
    public Pagination<T> getPaginationForSql(String sql, int currentPage, int numPerPage, Map<String, Object> map) {
        Session session = getSession();
        try {
            //获取计数
            String countSql = getCountHqlOrSql(sql);
            NativeQuery countQuery = session.createNativeQuery(countSql);
            setParameter(countQuery, map);
            int totalRows = getIntValue(countQuery.uniqueResult());

            //获取列表
            Query query = session.createNativeQuery(sql);
            setParameter(query, map);
            int offset = (currentPage - 1) * numPerPage;
            if (offset > 0) {
                query.setFirstResult(offset);
            }
            if (numPerPage > 0) {
                query.setMaxResults(numPerPage);
            }
            query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> list = query.list();
            return new Pagination<T>(currentPage, numPerPage, totalRows, null, list);
        } catch(HibernateException e) {
            log.error("执行sql错误！sql:{}",  sql, e);
            throw e;
        }
    }

    @Override
    public Integer getIntegerForSql(String sql) {
        Session session = getSession();
        try {
            Query query = session.createNativeQuery(sql);
            Object obj = query.uniqueResult();
            return obj == null ? null : getIntValue(obj);
        } catch(HibernateException e) {
            log.error("执行sql错误！sql:{}",  sql, e);
            throw e;
        }
    }

    @Override
    public boolean checkForSqlQuery(String sql) {
        Session session = getSession();
        try {
            Query query = session.createNativeQuery(sql);
            query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
            query.setMaxResults(1);
            query.list();
            return true;
        } catch(HibernateException e) {
            return false;
        }
    }

    @Override
    public Date getCurrentDatetime(){
        Session session = getSession();
        String sql = null;
        String hibernateDialect = HibernateTool.getHibernateDialect();
        if(HibernateTool.HIBERNATE_DIALECT_MYSQL.equals(hibernateDialect)){
            sql = " select now() ";
        }else if(HibernateTool.HIBERNATE_DIALECT_ORACLE.equals(hibernateDialect)){
            sql = " select sysdate from dual ";
        }else if(HibernateTool.HIBERNATE_DIALECT_SQLSERVER.equals(hibernateDialect)){
            sql = " select getdate() ";
        }else if(HibernateTool.HIBERNATE_DIALECT_DB2.equals(hibernateDialect)){
            sql = " select current timestamp from sysibm.sysdummy1 ";
        }else if(HibernateTool.HIBERNATE_DIALECT_POSTGRESQLDIALECT.equals(hibernateDialect)){
            sql = " select now() ";
        }
        Query query = session.createNativeQuery(sql);
        return (Date) query.uniqueResult();
    }

    @Override
    public Integer getColumnMaxIntegerValue(String column){
        Integer max = this.getInteger(" select max(" + column + ") from " + this.getPersistentClass().getName());
        return max == null ? 0 : max;
    }

    @Override
    public Long getColumnMaxLongValue(String column){
        Long max = this.getLong(" select max(" + column + ") from " + this.getPersistentClass().getName());
        return max == null ? 0 : max;
    }

    @Override
    public Integer getColumnMaxIntegerValue(String column, String where){
        Integer max = this.getInteger(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where);
        return max == null ? 0 : max;
    }

    @Override
    public Integer getColumnMaxIntegerValue(String column, String where, Object... params){
        Integer max = this.getInteger(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where, params);
        return max == null ? 0 : max;
    }

    @Override
    public Integer getColumnMaxIntegerValue(String column, String where, Map<String, Object> map){
        Integer max = this.getInteger(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where, map);
        return max == null ? 0 : max;
    }

    @Override
    public Long getColumnMaxLongValue(String column, String where){
        Long max = this.getLong(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where);
        return max == null ? 0 : max;
    }

    @Override
    public Long getColumnMaxLongValue(String column, String where, Object... params){
        Long max = this.getLong(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where, params);
        return max == null ? 0 : max;
    }

    @Override
    public Long getColumnMaxLongValue(String column, String where, Map<String, Object> map){
        Long max = this.getLong(" select max(" + column + ") from " + this.getPersistentClass().getName() +
                " where " + where, map);
        return max == null ? 0 : max;
    }

    /**
     * 检查为hql map语句
     * @param hql
     * @return
     */
    private void mapHqlCheck(String hql){
        if(!(hql != null && hql.toLowerCase().indexOf(" new ") > -1
                && hql.indexOf(" map") > hql.toLowerCase().indexOf(" new "))){
            log.error("hql语句非map查询，请使用 select new map(...) from ... hql:{}", hql);
            throw new IllegalArgumentException();
        }
    }

    private Session getSession(){
        try{
            return this.getSessionFactory().getCurrentSession();
        }catch(Exception ex){
            return getHibernateTemplate().getSessionFactory().openSession();
        }
    }

    /**
     * 获取当前的泛型T的类型type
     * @return
     */
    @SuppressWarnings("unchecked")
    protected Class<T> getPersistentClass(){
        if(this.persistentClass == null){
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return this.persistentClass;
    }

    /**
     * 获取表名
     * @return
     */
    @Override
    public String getTableName(){
        Class<T> clazz = this.getPersistentClass();
        Table table = clazz.getAnnotation(Table.class);
        if(table != null){
            return table.name();
        }
        return null;
    }

    private Float toFloat(Object obj){
        if(obj == null) {
            return null;
        }
        if(obj instanceof Double){
            return ((Double)obj).floatValue();
        }
        return (Float)obj;
    }

    private Integer toInteger(Object obj){
        if(obj == null) {
            return null;
        }
        if(obj instanceof BigInteger){
            return ((BigInteger)obj).intValue();
        }
        return (Integer)obj;
    }

    private Long toLong(Object obj){
        if(obj == null) {
            return null;
        }
        if(obj instanceof BigInteger){
            return ((BigInteger)obj).longValue();
        }
        return (Long)obj;
    }

    private int getIntValue(Object obj){
        if(obj == null) {
            return 0;
        }
        if(obj instanceof BigInteger){
            return ((BigInteger) obj).intValue();
        }else if(obj instanceof BigDecimal){
            return ((BigDecimal) obj).intValue();
        }else if(obj instanceof Integer){
            return ((Integer) obj).intValue();
        }
        return 0;
    }

    @Override
    public int excuteSql(String sql, Object... params){
        NativeQuery query = getSession().createNativeQuery(sql);
        int i = 0;
        for(Object obj : params){
            query.setParameter(i, obj);
            i++;
        }
        return query.executeUpdate();
    }

    @Override
    public int excuteSql(String sql, Map<String, Object> map){
        NativeQuery query = getSession().createNativeQuery(sql);
        setParameter(query, map);
        return query.executeUpdate();
    }


    /**
     * 执行sql
     * @param sql
     * @return
     */
    @Override
    public int excuteSql(String sql){
        NativeQuery query = getSession().createNativeQuery(sql);
        return query.executeUpdate();
    }

    /**
     * 保存Session中有两个持久化实体的情况
     * @param o
     * @return
     */
    @Override
    public T merge(T o){
        Session session = getSession();
        try{
            session.merge(o);
            return o;
        }catch(HibernateException e){
            log.error("保存或更新对象错误！", e);
            throw e;
        }
    }

    @Override
    public void setAutoIncrement(int increment){
        if(HibernateTool.HIBERNATE_DIALECT_MYSQL.equals(HibernateTool.getHibernateDialect())){
            String sql = " alter table " + this.getTableName() + " auto_increment = ? ";
            this.excuteSql(sql, increment);
        }
    }

    @Override
    public void setAutoIncrement(long increment){
        if(HibernateTool.HIBERNATE_DIALECT_MYSQL.equals(HibernateTool.getHibernateDialect())){
            String sql = " alter table " + this.getTableName() + " auto_increment = ? ";
            this.excuteSql(sql, increment);
        }
    }

    @Override
    public Integer getIntegerAutoIncrement(){
        if(HibernateTool.HIBERNATE_DIALECT_MYSQL.equals(HibernateTool.getHibernateDialect())){
            String sql = " select auto_increment from information_schema.tables where table_name = ? and table_schema = database() ";
            Object obj = this.getUniqueObjBySql(sql, this.getTableName());
            return toInteger(obj);
        }
        return null;
    }

    @Override
    public Long getLongAutoIncrement(){
        if(HibernateTool.HIBERNATE_DIALECT_MYSQL.equals(HibernateTool.getHibernateDialect())){
            String sql = " select auto_increment from information_schema.tables where table_name = ? and table_schema = database() ";
            Object obj = this.getUniqueObjBySql(sql, this.getTableName());
            return toLong(obj);
        }
        return null;
    }

    @Override
    public Object getUniqueObjBySql(String sql, Object... params){
        try{
            NativeQuery query = getSession().createNativeQuery(sql);
            int i = 0;
            for(Object obj : params){
                query.setParameter(i, obj);
                i++;
            }
            return query.uniqueResult();
        }catch(HibernateException e){
            log.error("执行sql错误！sql:{}",  sql, e);
            throw e;
        }
    }

    @SuppressWarnings("unchecked")
    public List<T> query(Criterion[] criterions, Projection[] projections, Order[] orders){
        Criteria criteria = getSession().createCriteria(getPersistentClass());
        if(criterions != null){
            for(Criterion criterion : criterions){
                criteria.add(criterion);
            }
        }
        if(projections != null){
            for(Projection projection : projections){
                criteria.setProjection(projection);
            }
        }
        if(orders != null){
            for(Order order : orders){
                criteria.addOrder(order);
            }
        }
        return criteria.list();
    }

    private Field[] getBeanFields(Class cls){
        Field[] fields = cls.getDeclaredFields();
        if(cls.getSuperclass() != null){
            Class clsSup = cls.getSuperclass();
            Field[] superFields = getBeanFields(clsSup);
            fields = (Field[]) ArrayUtils.addAll(fields, superFields);
        }
        return fields;
    }

    @Override
    public Set<String> getColumns(){
        Field[] fields = getBeanFields(this.getPersistentClass());
        Set<String> fieldSet = new HashSet<String>();
        for (int i = 0; i < fields.length; i++) {
            Annotation[] annotations = fields[i].getAnnotations();
            for (int j = 0; j < annotations.length; j++) {
                if (annotations[j] instanceof Column) {
                    Column column = (Column) annotations[j];
                    fieldSet.add(column.name());
                }
            }
        }
        return fieldSet;
    }

    @Override
    @SuppressWarnings("rawtypes")
    public Set<String> getColumns(Class classtype) {
        Field[] fields = getBeanFields(classtype);
        Set<String> fieldSet = new HashSet<String>();
        for (int i = 0; i < fields.length; i++) {
            Annotation[] annotations = fields[i].getAnnotations();
            for (int j = 0; j < annotations.length; j++) {
                if (annotations[j] instanceof Column) {
                    Column column = (Column) annotations[j];
                    fieldSet.add(column.name());
                }
            }
        }
        return fieldSet;
    }

    @Override
    public void deleteAll(){
        String hql = " delete from " + this.getPersistentClass().getName() +" where 1 = 1";
        this.execute(hql);
    }
}
